package ee.mtiidla.tuk.background;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;

import ee.mtiidla.data.AgeGroup;
import ee.mtiidla.data.Athlete;
import ee.mtiidla.data.Club;
import ee.mtiidla.data.Event;
import ee.mtiidla.data.Lenex;
import ee.mtiidla.data.Meet;
import ee.mtiidla.data.Ranking;
import ee.mtiidla.data.Relay;
import ee.mtiidla.data.Result;
import ee.mtiidla.io.FileReader;
import ee.mtiidla.tuk.data.AgeGroupOrder;
import ee.mtiidla.tuk.data.Constants;
import ee.mtiidla.tuk.data.RankingOrder;
import ee.mtiidla.tuk.data.Template;
import ee.mtiidla.utils.Utils;

/**
 * Created by Marko on 12.10.2014.
 */
public abstract class SlideWriter extends Thread {

	private File mOutputDirectory;
	private String mTemplate;

	private Lenex mLenex;

	private List<Event> mEvents;

	private RankingOrder mRankingOrder;
	private AgeGroupOrder mAgeGroupOrder;

	private LinkedHashMap<Long, Athlete> mAthleteMap;
	private LinkedHashMap<Long, Athlete> mAthleteResultMap;
	private LinkedHashMap<Long, Relay> mRelayResultMap;
	private LinkedHashMap<Long, Result> mResultMap;

	protected SlideWriter(File outputDir, File template, Lenex lenex, List<Event> events,
	                      RankingOrder rankingOrder, AgeGroupOrder ageGroupOrder) {
		mOutputDirectory = outputDir;
		try {
			mTemplate = FileReader.readTemplateFile(template);
		} catch (IOException e) {
			onError(e);
		}
		mLenex = lenex;
		mEvents = events;
		mRankingOrder = rankingOrder;
		mAgeGroupOrder = ageGroupOrder;
	}

	@Override
	public void run() {
		super.run();

		if (mEvents.isEmpty()) {
			return;
		}

		Meet meet = mLenex.getMeets().get(0);

		String directory = "Autasustamine - " + meet.getName();

		File output = new File(mOutputDirectory, directory);

		output.mkdirs();

		if (!output.exists()) {
			onError(new IOException("Slides output directory cannot be created"));
			return;
		}

		mAthleteResultMap = new LinkedHashMap<Long, Athlete>();
		mRelayResultMap = new LinkedHashMap<Long, Relay>();
		mResultMap = new LinkedHashMap<Long, Result>();
		mAthleteMap = new LinkedHashMap<Long, Athlete>();

		for (Club club : meet.getClubs()) {
			if (club.getAthletes() != null) {
				for (Athlete athlete : club.getAthletes()) {
					athlete.setClub(club);
					if (athlete.getResults() != null) {
						for (Result result : athlete.getResults()) {
							mAthleteResultMap.put(result.getResultId(), athlete);
							mResultMap.put(result.getResultId(), result);
						}
					}
					mAthleteMap.put(athlete.getAthleteId(), athlete);
				}
			}
			if (club.getRelays() != null) {
				for (Relay relay : club.getRelays()) {
					relay.setClub(club);
					if (relay.getResults() != null) {
						for (Result result : relay.getResults()) {
							mRelayResultMap.put(result.getResultId(), relay);
							mResultMap.put(result.getResultId(), result);
						}
					}
				}
			}
		}

		for (Event event : mEvents) {

			if (Utils.isEmpty(event.getAgeGroups())) continue;

			File eventDir = new File(output, event.toString());

			deleteDir(eventDir);
			eventDir.mkdirs();

			if (!eventDir.exists()) {
				onError(new IOException("Slides output directory cannot be created"));
				continue;
			}

			String prevFile = null;
			String nextFile;

			for (ListIterator<AgeGroup> i = event.getAgeGroups().listIterator(); i.hasNext(); ) {
				AgeGroup ageGroup = i.next();
				if (Utils.isEmpty(ageGroup.getRankings())) {
					i.remove();
				} else {
					for (ListIterator<Ranking> j = ageGroup.getRankings().listIterator(); j.hasNext(); ) {
						Ranking ranking = j.next();
						if (ranking.getPlace() <= -1 || ranking.getPlace() > Constants.MAX_NO_PLACES) {
							j.remove();
						}
					}
					if (Utils.isEmpty(ageGroup.getRankings())) {
						i.remove();
					} else {
						ageGroup.setGender(event.getGender());
					}
				}
			}

			List<AgeGroup> ageGroups = new ArrayList<AgeGroup>(event.getAgeGroups());

			if (mAgeGroupOrder == AgeGroupOrder.YOUNGEST_LAST) {
				Collections.reverse(ageGroups);
			}
			int order = 0;
			for (int i = 0; i < ageGroups.size(); i++) {
				AgeGroup ageGroup = ageGroups.get(i);
				List<Ranking> rankings = new ArrayList<Ranking>(ageGroup.getRankings());
				AgeGroup nextAgeGroup = null;
				List<Ranking> nextRankings = null;
				if (i < ageGroups.size() - 1) {
					nextAgeGroup = ageGroups.get(i + 1);
					nextRankings = new ArrayList<Ranking>(nextAgeGroup.getRankings());
				}
				if (mRankingOrder == RankingOrder.WINNER_LAST) {
					Collections.reverse(rankings);
					if (nextRankings != null) {
						Collections.reverse(nextRankings);
					}
				}
				for (int j = 0; j < rankings.size(); j++) {
					order++;
					Ranking ranking = rankings.get(j);
					if (j < rankings.size() - 1) {
						nextFile = generateRankingFileName(order + 1, ageGroup, rankings.get(j + 1));
					} else if (nextAgeGroup != null) {
						nextFile = generateRankingFileName(order + 1, nextAgeGroup, nextRankings.get(0));
					} else {
						nextFile = null;
					}
					prevFile = writeSlideShowFile(eventDir, prevFile, nextFile, order, ageGroup, event, ranking);
				}
			}
		}

		onOutputDone(mLenex);

	}


	public abstract void onOutputDone(Lenex lenex);

	public abstract void onError(Exception e);

	private void deleteDir(File dir) {

		if (dir.isDirectory()) {
			for (File file : dir.listFiles()) {
				deleteDir(file);
			}
		}

		dir.delete();

	}

	private String writeSlideShowFile(File eventDir, String prevFile, String nextFile,
	                                  int order, AgeGroup ageGroup, Event event, Ranking ranking) {

		String output = mTemplate;

		Athlete athlete = mAthleteResultMap.get(ranking.getResultId());
		if (athlete != null) {
			output = output.replace(Template.FIRST_NAME, athlete.getFirstName());
			output = output.replace(Template.LAST_NAME, athlete.getLastName());
			output = output.replace(Template.CLUB, athlete.getClub().getCode());
		} else {
			Relay relay = mRelayResultMap.get(ranking.getResultId());
			if (relay != null) {
				output = output.replace(Template.FIRST_NAME, relay.getClub().getName() + " " + relay.getNumber());
			}
		}

		Result result = mResultMap.get(ranking.getResultId());
		if (result != null) {
			output = output.replace(Template.TIME, result.getSwimtimeShort());
		}

		output = output.replace(Template.PLACE, ranking.getPlaceRoman());
		output = output.replace(Template.EVENT, event.toString());
		output = output.replace(Template.NEXT_PAGE, String.valueOf(nextFile));
		output = output.replace(Template.PREV_PAGE, String.valueOf(prevFile));

		//Clear template file in case of missing data
		output = output.replace(Template.FIRST_NAME, "");
		output = output.replace(Template.LAST_NAME, "");
		output = output.replace(Template.CLUB, "");
		output = output.replace(Template.TIME, "");

		String rankingFileName = generateRankingFileName(order, ageGroup, ranking);

		File rankingFile = new File(eventDir, rankingFileName);
		try {
			if (rankingFile.createNewFile()) {
				Files.write(rankingFile.toPath(), output.getBytes("UTF-8"));
			}
		} catch (IOException e) {
			onError(e);
		}

		return rankingFile.getName();
	}

	private String generateRankingFileName(int order, AgeGroup ageGroup, Ranking ranking) {
		return order + ". " + ageGroup.toString() + " " + ranking.getPlaceRoman() + ".html";
	}
}
